package com.realshare.frame.component.quartz;

import com.realshare.frame.FrameWebApplication;
import com.realshare.frame.component.quartz.base.AutoScheduler;
import com.realshare.frame.component.quartz.base.BaseScheduler;
import com.realshare.frame.component.quartz.service.DBQuartzScheduler;
import com.realshare.frame.component.quartz.service.QuartzManager;
import com.realshare.frame.core.config.CustomPropertiesConfig;
import org.apache.commons.lang3.StringUtils;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 定制任务调度器
 * author leisure
 * email 15075107120@139.com
 * create 2018-11-23 下午 5:53
 * modify 2018-11-23 下午 5:53
 **/
@Component
public class QuartzInit implements ApplicationListener<ApplicationReadyEvent> {

    private Logger log = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private CustomPropertiesConfig propertiesConfig;
    @Autowired
    private DBQuartzScheduler dbDataHandlerTask;
    @Autowired
    private QuartzManager quartzManager;

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        log.info("Springboot容器初始化完成。");
        initSchedule(event);
        dbDataHandlerTask.init();
    }

    /**
     * 初始化定制任务处理器
     *
     * @param event application
     */
    @SuppressWarnings("unchecked")
    private void initSchedule(ApplicationReadyEvent event) {
        log.info("开始初始化定制定时任务");
        String packageStr = FrameWebApplication.class.getPackage().getName();
        Map<String, String> scheduleMap = new HashMap<String, String>();
        //反射工具包，指明扫描路径
        Reflections reflections = new Reflections(packageStr);
        //获取带AutoSchedule注解的类
        Set<Class<?>> classList = reflections.getTypesAnnotatedWith(AutoScheduler.class);
        Map<String, String> scheduleConfig = propertiesConfig.getSchedule();
        for (Class classes : classList) {
            AutoScheduler t = (AutoScheduler) classes.getAnnotation(AutoScheduler.class);
            String value = t.value();
            final String name = StringUtils.isNotBlank(t.name()) ? t.name() : value;
            final String group = StringUtils.isNotBlank(t.group()) ? t.group() : StringUtils.isNotBlank(name) ? name : value;
            String className = classes.getName();
            if (StringUtils.isEmpty(name)) {
                log.error("\u001b[31m 定时任务注解错误，正确格式为“AutoSchedule(任务名称)”，错误任务路径为：“" + className + "”，请处理后再重启服务！");
                event.getApplicationContext().close();
                return;
            }
            if (scheduleMap.get(name) != null) {
                log.error("\u001b[31m 定时任务重复，名称为：”" + value + "“，重复任务路径为：“" + className + "”，请处理后再重启服务！");
                event.getApplicationContext().close();
                return;
            }
            scheduleMap.put(name, "");
            BaseScheduler schedule = getClass(className);
            if (schedule != null) {
                String cron = scheduleConfig.get(name);
                if (!quartzManager.isValidExpression(cron)) {
                    break;
                }
                String description = schedule.getDescription();
                log.info("正在初始化定制定时任务【" + name + "】...");
                quartzManager.scheduleJob(name, group, description, cron, schedule.getClass());

                //是否在服务启动后立即执行一次任务
                if (schedule.isTriggerByServiceStart()) {
                    Runnable runnable = new Runnable() {
                        @Override
                        public void run() {
                            try {
                                Thread.sleep(10000);
                                log.info("服务启动后立即执行一次定时任务【" + name + "】");
                                quartzManager.triggerJob(name, group);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    };
                    new Thread(runnable).start();
                }
            }
        }
        log.info("结束初始化定制定时任务");
    }

    private static BaseScheduler getClass(String classname) {
        try {
            Class<?> class1 = Class.forName(classname);
            return (BaseScheduler) class1.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}